﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
[Serializable]
public class SMRInfo
{
    public SkinnedMeshRenderer smr;
    public Transform[] bones;
}
public class ManualGizmos : MonoBehaviour
{
    public List<Transform> balls;
    public List<Transform> sections;
    public GizmosAxis axis;
    public HairUnitEmitter hue;
    public Material selected;
    public Material unSelected;
    public Transform ballsParent;
    public GameObject sectionScaleSlidersGO;
    public LabelSlider sectionWidthSlider;
    public Vector3 sectionWidthMOM;
    public SMRInfo[] smrInfos;
    public bool ignoreChanged;
    public bool _init;
    public int index;
    public List<int> controlIndices;
    public List<Vector3> originPositions;
    public float world2ScreenRatio;

    public GameObject seletorBlock;
    public LabelSlider sectionThicknessSlider;
    public Vector3 sectionThicknessMOM;

    public List<Vector3[]> originPosAll;
    bool quiting = false;
    public bool ignoreClick = true;
    public Vector3 ignorePos;
    public float ignorePosKeepDist;
    public Mesh Bake(SMRInfo smrInfo, Mesh originMesh)
    {
        var baked = new Mesh();
        smrInfo.smr.BakeMesh(baked);
        baked.name = "Baked Mesh";
        baked.bindposes = originMesh.bindposes;
        baked.boneWeights = originMesh.boneWeights;
        return baked;
    }
    public void OnSectionThicknessChanged(float v)
    {
        if (ignoreChanged || index < 0 || index > 7 || hue.scaler.unitsSelected.Count == 0) return;
        foreach (var unit in hue.scaler.unitsSelected)
        {
            unit.sectionThickness[index] = v;
            UpdateUnitScale(unit);
            if (unit.mirror != null && SliderMgr.mirrorControl)
            {
                unit.mirror.sectionThickness[index] = v;
                UpdateUnitScale(unit.mirror);
            }
        }
    }
    void OnSectionWidthChanged(float v)
    {
        if (ignoreChanged || index < 0 || index > 7 || hue.scaler.unitsSelected.Count == 0) return;
        foreach (var unit in hue.scaler.unitsSelected)
        {
            unit.sectionWidth[index] = v;
            UpdateUnitScale(unit);
            if (unit.mirror != null && SliderMgr.mirrorControl)
            {
                unit.mirror.sectionWidth[index] = v;
                UpdateUnitScale(unit.mirror);
            }
        }
    }
    public void AllSectionWidthChanged(float v)
    {
        if (ignoreChanged || hue.scaler.unitsSelected.Count == 0) return;
        foreach (var unit in hue.scaler.unitsSelected)
        {
            UnitSectionWidthChange(unit, v);
            if (unit.mirror != null && SliderMgr.mirrorControl)
            {
                UnitSectionWidthChange(unit.mirror, v);
            }
        }
    }
    void UnitSectionWidthChange(HairUnit unit, float v)
    {
        for (int i = 0; i < unit.sectionWidth.Length; i++)
        {
            unit.sectionWidth[i] = v;
        }
        UpdateUnitScale(unit);
    }
    public void AllSectionThicknessChanged(float v)
    {
        if (ignoreChanged || hue.scaler.unitsSelected.Count == 0) return;
        foreach (var unit in hue.scaler.unitsSelected)
        {
            UnitSectionThicknesssChange(unit, v);
            if (unit.mirror != null && SliderMgr.mirrorControl)
            {
                UnitSectionThicknesssChange(unit.mirror, v);
            }
        }
    }
    void UnitSectionThicknesssChange(HairUnit unit, float v)
    {
        for (int i = 0; i < unit.sectionThickness.Length; i++)
        {
            unit.sectionThickness[i] = v;
        }
        UpdateUnitScale(unit);
    }
    public void UpdateUnitScale(HairUnit unit)//ThicknessAndWidth
    {
        var t = unit.endType;
        for (int i = 0; i < unit.sectionThickness.Length; i++)
        {
            var width = unit.sectionWidth[i];
            var thickness = unit.sectionThickness[i];
            smrInfos[t].bones[i].localScale = i == 0 ? new Vector3(width, 1f, thickness) : new Vector3(thickness, 1f, width);
        }
        unit.smr.sharedMesh = Bake(smrInfos[t], hue.endTypeMeshs[t]);
        unit.UpdateColliderAndSectionTrans();
    }
    public void Init()
    {
        index = -1;
        if (_init) return;
        _init = true;
        axis.GetOriginCallBack = GetOriginCallBack;
        sectionWidthSlider.Init(sectionWidthMOM, OnSectionWidthChanged);
        sectionThicknessSlider.Init(sectionThicknessMOM, OnSectionThicknessChanged);
        var bs = ballsParent.GetComponentsInChildren<SphereCollider>(true);
        balls = new List<Transform>();
        for (int i = 0; i < bs.Length; i++)
        {
            balls.Add(bs[i].transform);
        }
        sections = new List<Transform>();
        originPosAll = new List<Vector3[]>();
    }    
    void GetOriginCallBack()
    {
        originPositions.Clear();
        for (int i = 0; i < sections.Count; i++)
        {
            originPositions.Add(sections[i].position);
        }
        originPosAll.Clear();
        var unitSel = hue.scaler.unitsSelected;
        for (int i = 0; i < unitSel.Count; i++)
        {
            var secs = unitSel[i].GetComponentsInChildren<UnityChan.SpringBone>();
            var ss = new Vector3[secs.Length];
            for (int s = 0; s < secs.Length; s++)
            {
                ss[s] = secs[s].transform.position;
            }
            originPosAll.Add(ss);
        }
    }
    private void OnEnable()
    {
        seletorBlock.SetActive(true);
        foreach (var ball in balls)
        {
            if (ball != axis.controlObj)
                ball.GetComponent<Renderer>().material = unSelected;
            else
                ball.GetComponent<Renderer>().material = selected;
        }
    }    
    private void OnApplicationQuit()
    {
        quiting = true;
    }
    private void OnDisable()
    {
        if (quiting) return;
        seletorBlock.SetActive(false);
        sectionScaleSlidersGO.SetActive(false);
        if (axis == null) return;
        axis.controlObj = null;
        axis.gameObject.SetActive(false);
    }
    void Update()
    {
        bool bHit = false;
        if (Input.GetMouseButtonDown(0))
        {
            var mask = 1 << LayerMask.NameToLayer("Gizmos");
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            float dist = Mathf.Infinity;
            RaycastHit hit;
            //是否同时击中坐标轴
            bHit = Physics.Raycast(ray, out hit, dist, mask, QueryTriggerInteraction.Collide);
            if (!ignoreClick)
            {
                if (Vector3.Distance(ignorePos, Input.mousePosition) > ignorePosKeepDist)
                {
                    ignoreClick = true;
                }
            }
            if (bHit && ignoreClick) // 给坐标轴让位
            {
                // 但是同一位置再点击一次就不让了                
                ignoreClick = false;
                ignorePos = Input.mousePosition;
            }
            else
            {
                ignoreClick = true;
                mask = 1 << LayerMask.NameToLayer("GizmosBalls");
                bHit = Physics.Raycast(ray, out hit, dist, mask, QueryTriggerInteraction.Collide);
                if (bHit)
                {
                    GetOriginCallBack();
                    axis.controlObj = hit.transform;
                    axis.gameObject.SetActive(true);
                    sectionScaleSlidersGO.SetActive(true);
                }
                foreach (var ball in balls)
                {
                    if (ball != axis.controlObj)
                        ball.GetComponent<Renderer>().material = unSelected;
                    else
                        ball.GetComponent<Renderer>().material = selected;
                }
            }
        }
        if (hue.scaler.unitsSelected.Count == 0)
            return;

        var unit = hue.scaler.unitsSelected[0];

        index = -1;
        for (int i = 0; i < balls.Count; i++)
        {
            if (balls[i] == axis.controlObj)
                index = i;
        }
        if (index < 0) return; // 无选择小球
        if (bHit && index < 8)
        {
            ignoreChanged = true;
            sectionWidthSlider.value = unit.sectionWidth[index];
            sectionThicknessSlider.value = unit.sectionThickness[index];
            ignoreChanged = false;
        }
        var ppRange = hue.sdMgr.proportionalEditRangeValue;
        float factor = ppRange == 0f ? 0f : 1f / ppRange;
        var relativePos = balls[index].position - originPositions[index]; //记录相对移动位置
        var us = hue.scaler.unitsSelected;
        for (int i = 0; i < sections.Count; i++)
        {
            var dis = Vector3.Distance(originPositions[index], originPositions[i]) * world2ScreenRatio;
            if ((hue.sdMgr.proportionalEditOn && dis < ppRange) || i == index)
            {
                float weight = i == index ? 1f : 1f - dis * factor; // 根据权重（衰减范围）移动骨骼
                if (i > index && !hue.sdMgr.manualKeepChildPosOn)
                    weight = 1f; // 同时控制下方头发

                for (int u = 0; u < us.Count; u++)
                {
                    if (unit == us[u]) continue;
                    var otherSections = us[u].GetComponentsInChildren<UnityChan.SpringBone>();
                    otherSections[i].transform.position = originPosAll[u][i] + relativePos * weight;
                }
                sections[i].position = originPositions[i] + relativePos * weight;
            }
            else
            {
                if (hue.sdMgr.manualKeepChildPosOn || i < index)// 保持上下方骨骼不变
                {
                    for (int u = 0; u < us.Count; u++)
                    {
                        if (unit == us[u]) continue;
                        var otherSections = us[u].GetComponentsInChildren<UnityChan.SpringBone>();
                        otherSections[i].transform.position = originPosAll[u][i];
                    }
                    sections[i].position = originPositions[i];
                }
            }
        }
        for (int i = 0; i < sections.Count; i++)
        {
            var dis = Vector3.Distance(originPositions[index], originPositions[i]) * world2ScreenRatio;
            if (!(dis < ppRange || i == index)) continue;
            // 使父骨骼朝向当前骨骼，当前骨骼朝向子骨骼
            if (hue.sdMgr.manualKeepLookAtRotOn && sections[i].position != originPositions[i])
            {
                foreach (var u in us)
                {
                    SetLookAtChild(u.baker.bones[index].parent);
                    SetLookAtChild(u.baker.bones[index]);
                    if (u.mirror !=null)
                    {
                        SetLookAtChild(u.mirror.baker.bones[index].parent);
                        SetLookAtChild(u.mirror.baker.bones[index]);
                    }
                }
            }
        }
        if (SliderMgr.mirrorControl) // 完全镜像形状
        {
            for (int u = 0; u < us.Count; u++)
            {
                if (us[u].mirror == null) continue;
                var otherSections = us[u].GetComponentsInChildren<UnityChan.SpringBone>();
                var otherSectionsMirror = us[u].mirror.GetComponentsInChildren<UnityChan.SpringBone>();
                for (int i = 0; i < otherSections.Length; i++)
                {
                    otherSectionsMirror[i].transform.position = Vector3.Scale(otherSections[i].transform.position, new Vector3(-1, 1, 1));
                }
            }
        }
        // 小球跟随下方骨骼移动
        for (int i = 0; i < sections.Count; i++)
        {
            balls[i].position = sections[i].transform.position;
            balls[i].rotation = sections[i].transform.rotation;
        }
    }
    void SetLookAtChild(Transform t)
    {
        var absolutePos = t.position;
        var c = t.GetChild(0);
        var absolutePosC = c.position; // 记录原来的绝对位置
        var absoluteRotC = c.rotation; // 绝对旋转
        var iDir = (absolutePosC - absolutePos).normalized;
        var iRot = Quaternion.FromToRotation(t.up, iDir);
        t.rotation = iRot * t.rotation;
        c.position = absolutePosC;
        c.rotation = absoluteRotC;
    }
}
